package com.lry.pda.topdown;

import com.lry.pda.Attribute;
import com.lry.pda.Lexer;
import com.lry.pda.Register;

import java.util.Stack;

import static com.lry.pda.topdown.SymbolDefine.*;

/**
 * 带值栈的下推自动机
 * ll(1)型语法是上下文无关文法的子集
 * 需要消除左递归，提公共左因子
 *
 * stmt -> {0} expr {1} semi stmt | EOI
 * expr -> term exprPrime
 * exprPrim -> plus {0} term {2} exprPrim | 空
 * term -> factor termPrime
 * termPrime -> time {0} factor {3} termPrime | 空
 * factor -> num {4} | ( expr )
 *
 */
public class TopdownPdaParser {

    //逆向将表达式压入栈中，遍历栈的时候发现栈顶是终结符，则终结符必须和lexer当前yytext匹配，若栈顶是非终结符，逆向将表达式压入栈中
    private Stack<Integer> stack = new Stack<>();
    private Register register = new Register();
    private Stack<Attribute> valueStack = new Stack<>();
    private Lexer lexer;
    private Attribute parent = Attribute.getAttribute(new Attribute.KV());
//    private ParseTable parseTable = new ParseTable();
    private ParseTableBuilder parseTable = new ParseTableBuilder();

    public static void main(String[] args) {
        TopdownPdaParser pdaParser = new TopdownPdaParser(new Lexer());
        pdaParser.parse();
    }


    public TopdownPdaParser(Lexer lexer){
        this.lexer = lexer;
        this.lexer.input();
        this.lexer.advance();
        push(SymbolDefine.STMT);
    }

    private void pop(){
        stack.pop();
        parent = valueStack.pop();
    }

    private void push(Integer grammar){
        stack.push(grammar);

        Attribute attribute = Attribute.getAttribute(parent.right);
        valueStack.push(attribute);
    }

    public void parse(){
        while(!stack.isEmpty()){
            Integer grammar = stack.peek();
            switch (grammar){

                //申请内存
                case ACTION_0:
                    stack.pop();
                    String name = register.getName();
                    int size = valueStack.size();
                    //将栈顶下面两个位置的right置为name

                    valueStack.get(size-2).right.key = name;
                    valueStack.get(size-3).right.key = name;

                    valueStack.pop();
                    break;

                    //释放内存
                case ACTION_1:
                    stack.pop();
                    Attribute attr = valueStack.pop();
                    name = attr.right.key;
                    register.free(name);
                    System.out.println("free "+name);
                    break;

                    //+=
                case ACTION_2:
                    stack.pop();
                    attr = valueStack.pop();
                    System.out.println(attr.left.key +" += " +attr.right.key);

                    attr.left.value += attr.right.value;
                    System.out.println(attr.left.key +" = " + attr.left.value);
                    //修改值栈
                    changeValue(attr.left.key,attr.left.value);

                    register.free(attr.right.key);
                    System.out.println("free "+attr.right.key);
                    break;

                    //*=
                case ACTION_3:
                    stack.pop();
                    attr = valueStack.pop();
                    System.out.println(attr.left.key +" *= " +attr.right.key);

                    attr.left.value *= attr.right.value;
                    System.out.println(attr.left.key +" = " + attr.left.value);

                    //修改值栈
                    changeValue(attr.left.key,attr.left.value);

                    register.free(attr.right.key);
                    System.out.println("free "+attr.right.key);
                    break;

                    //赋值
                case ACTION_4:
                    stack.pop();
                    attr = valueStack.pop();

                    changeValue(attr.right.key,Integer.valueOf(lexer.yytext));

                    System.out.println(attr.right.key +" = " +lexer.yytext);
                    lexer.advance();
                    break;


                case NUM_OR_ID:
                    pop();
                    if(!lexer.match(Lexer.NUM_OR_ID)){
                        parseError();
                    }
                    //ACTION_4赋值语句需要yytext，所以此时不advance
//                    lexer.advance();
                    break;

                case PLUS:
                    pop();
                    if(!lexer.match(Lexer.PLUS)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case SEMI:
                    pop();
                    if(!lexer.match(Lexer.SEMI)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case TIMES:
                    pop();
                    if(!lexer.match(Lexer.TIMES)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case LP:
                    pop();
                    if(!lexer.match(Lexer.LP)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case RP:
                    pop();
                    if(!lexer.match(Lexer.RP)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                default:
                    int whatToDo = parseTable.getWhatToDo(grammar, lexer.lookAhead);
                    if (whatToDo == -1) {
                        parseError();
                    } else {
                        pop();
                        int[] replaceSymbols = parseTable.getPushTabItems(whatToDo);
                        if (replaceSymbols != null) {
                            for (int i = 0; i < replaceSymbols.length; i++) {
                                push(replaceSymbols[i]);
                            }
                        }

                    }
                    break;
            }
        }

        System.out.println("PDA accept");
    }



    private void changeValue(String key,Integer value){
        //遍历值栈找到所有key是t0||t1...的，把value改成value
        for (Attribute attribute : valueStack) {
            if(key.equals(attribute.left.key)){
                attribute.left.value = value;
            }
            if(key.equals(attribute.right.key)){
                attribute.right.value = value;
            }
        }
    }

    private void parseError() {
        System.err.println("PDA parse error");
        System.exit(1);
    }

}
